﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Net;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Web;
using HtmlAgilityPack;
using log4net;

namespace Cnm.Core.Ultities
{
    public static class CommonHelpers
    {
        private static readonly ILog Log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);

        private static readonly string[] VietnameseSigns = new[]
                                                               {
                                                                   "aAeEoOuUiIdDyY",
                                                                   "áàạảãâấầậẩẫăắằặẳẵ",
                                                                   "ÁÀẠẢÃÂẤẦẬẨẪĂẮẰẶẲẴ",
                                                                   "éèẹẻẽêếềệểễ",
                                                                   "ÉÈẸẺẼÊẾỀỆỂỄ",
                                                                   "óòọỏõôốồộổỗơớờợởỡ",
                                                                   "ÓÒỌỎÕÔỐỒỘỔỖƠỚỜỢỞỠ",
                                                                   "úùụủũưứừựửữ",
                                                                   "ÚÙỤỦŨƯỨỪỰỬỮ",
                                                                   "íìịỉĩ",
                                                                   "ÍÌỊỈĨ",
                                                                   "đ",
                                                                   "Đ",
                                                                   "ýỳỵỷỹ",
                                                                   "ÝỲỴỶỸ"
                                                               };
        public static readonly List<string> Sex = new List<string> { "Anh", "Chị" };

        public static string RemoveVietnameseSign(string str)
        {
            for (int i = 1; i < VietnameseSigns.Length; i++)
            {
                for (int j = 0; j < VietnameseSigns[i].Length; j++)
                    str = str.Replace(VietnameseSigns[i][j], VietnameseSigns[0][i - 1]);
            }
            return str;
        }

        public static string ToCleanVietnameseSign(this string str)
        {
            return RemoveVietnameseSign(str);
        }

        public static string GetCurrentMethod(MethodBase methodBase)
        {
            var declaringType = MethodBase.GetCurrentMethod().DeclaringType;
            if (declaringType != null)
            {
                return string.Format("{0}.{1}", declaringType.FullName, MethodBase.GetCurrentMethod().Name);
            }
            return "";
        }

        public static string Title2Alias(string title)
        {
            if (string.IsNullOrWhiteSpace(title))
                return string.Empty;

            title = title.Trim();

            title = RemoveVietnameseSign(title);

            // make it all lower case
            title = title.ToLower();
            // remove entities
            title = Regex.Replace(title, @"&\w+;", "");
            // remove anything that is not letters, numbers, dash, or space
            title = Regex.Replace(title, @"[^a-z0-9\-\s]", "");
            // replace spaces
            title = title.Replace(' ', '-');
            // collapse dashes
            title = Regex.Replace(title, @"-{2,}", "-");
            // trim excessive dashes at the beginning
            title = title.TrimStart(new[] { '-' });
            // if it's too long, clip it
            if (title.Length > 80)
                title = title.Substring(0, 79);
            // remove trailing dashes
            title = title.TrimEnd(new[] { '-' });

            return title;
        }

        public static string ToAlias(this string title)
        {
            return Title2Alias(title);
        }

        /// <summary>
        /// Converts to html to plain-text.
        /// </summary>
        /// <param name="html">The html.</param>
        /// <returns>The plain text representation of the html</returns>
        public static string ConvertToText(string html)
        {
            html = "<div id=\"new\">" + html + "</div>";

            var doc = new HtmlDocument();
            doc.LoadHtml(html);

            return doc.DocumentNode.SelectNodes("//text()").Aggregate("", (current, node) => current + node.InnerText);
        }

        /// <summary>
        /// Converts to html to plain-text.
        /// </summary>
        /// <param name="html">The html.</param>
        /// <param name="length">leng of text </param>
        /// <returns>The plain text representation of the html</returns>
        public static string ConvertToText(string html, int length)
        {
            try
            {
                html = "<div id=\"new\">" + html + "</div>";

                var doc = new HtmlDocument();
                doc.LoadHtml(html);
                var text = "";
                var nodes = doc.DocumentNode.SelectNodes("//text()");
                if (nodes == null)
                    return text;
                foreach (HtmlNode node in nodes)
                {
                    text += node.InnerText;
                    if (text.Length >= length)
                        return SafeSubString(text, length);
                }

                return text;
            }
            catch
            {
                return "";
            }
        }

        public static string RemoveAllHtmlFormatButKeepNewLine(string html)
        {
            if (string.IsNullOrWhiteSpace(html))
                return string.Empty;

            var output = new StringBuilder();
            var doc = new HtmlDocument();
            doc.LoadHtml("<div id=\"new\">" + html + "</div>");
            var nodes = doc.DocumentNode.SelectNodes("//*");
            var htmlNode = nodes.FirstOrDefault();
            if (htmlNode != null)
                output.AppendLine(htmlNode.InnerText.ToString(CultureInfo.InvariantCulture) + "\n");
            var result = Regex.Replace(output.ToString(), @"(?:\r\n|\r(?!\n)|(?!<\r)\n){2,}", Environment.NewLine);
            // Remove all tab
            result = result.Replace("\t", String.Empty);
            // Remove all duplicate new line
            var results = result.Split(Environment.NewLine.ToCharArray());
            result = "";
            foreach (var str in results)
            {
                if (string.IsNullOrWhiteSpace(str))
                    continue;
                result += str.Trim() + Environment.NewLine;
            }
            return result;
        }

        public static string SafeSubString(string text, int length)
        {
            if (length <= 0)
                return string.Empty;

            if (string.IsNullOrWhiteSpace(text))
                return text;

            if (text.Length <= length)
                return text;

            while (text[length - 1] != ' ')
            {
                length--;
            }

            return text.Substring(0, length);
        }
        public static string GetFirstImg(string html)
        {
            try
            {
                html = "<div id=\"new\">" + html + "</div>";

                var doc = new HtmlDocument();
                doc.LoadHtml(html);
                var node = doc.DocumentNode.SelectSingleNode("//img");
                if (node == null)
                    return "/Images/image-not-found.gif";
                var img = node.GetAttributeValue("src", null);
                return string.IsNullOrWhiteSpace(img) ? "/Images/image-not-found.gif" : img;
            }
            catch
            {
                return "/Images/image-not-found.gif";
            }
        }

        public static string GetClientIpAddress(HttpRequestBase request)
        {
            try
            {
                var userHostAddress = request.UserHostAddress;

                // Attempt to parse.  If it fails, we catch below and return "0.0.0.0"
                // Could use TryParse instead, but I wanted to catch all exceptions
                if (userHostAddress != null) IPAddress.Parse(userHostAddress);

                var xForwardedFor = request.ServerVariables["X_FORWARDED_FOR"];

                if (string.IsNullOrEmpty(xForwardedFor))
                    return userHostAddress;

                // Get a list of public ip addresses in the X_FORWARDED_FOR variable
                var publicForwardingIps = xForwardedFor.Split(',').Where(ip => !IsPrivateIpAddress(ip)).ToList();

                // If we found any, return the last one, otherwise return the user host address
                return publicForwardingIps.Any() ? publicForwardingIps.Last() : userHostAddress;
            }
            catch (Exception)
            {
                // Always return all zeroes for any failure (my calling code expects it)
                return "0.0.0.0";
            }
        }

        private static bool IsPrivateIpAddress(string ipAddress)
        {
            // http://en.wikipedia.org/wiki/Private_network
            // Private IP Addresses are: 
            //  24-bit block: 10.0.0.0 through 10.255.255.255
            //  20-bit block: 172.16.0.0 through 172.31.255.255
            //  16-bit block: 192.168.0.0 through 192.168.255.255
            //  Link-local addresses: 169.254.0.0 through 169.254.255.255 (http://en.wikipedia.org/wiki/Link-local_address)

            var ip = IPAddress.Parse(ipAddress);
            var octets = ip.GetAddressBytes();

            var is24BitBlock = octets[0] == 10;
            if (is24BitBlock) return true; // Return to prevent further processing

            var is20BitBlock = octets[0] == 172 && octets[1] >= 16 && octets[1] <= 31;
            if (is20BitBlock) return true; // Return to prevent further processing

            var is16BitBlock = octets[0] == 192 && octets[1] == 168;
            if (is16BitBlock) return true; // Return to prevent further processing

            var isLinkLocalAddress = octets[0] == 169 && octets[1] == 254;
            return isLinkLocalAddress;
        }
        
        public static DateTime ToDateTime(this string dateTime, string pattern = "d/M/yyyy")
        {
            dateTime = dateTime.Split(' ')[0];
            var value = DateTime.Now;
            DateTime.TryParseExact(dateTime, pattern, null, DateTimeStyles.None, out value);

            return value;
        }
    }
}
